﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel.DataAnnotations;


namespace slTestingStreaming.Framework
{
    public abstract class Bindable : DependencyObject, INotifyPropertyChanged, IEnumerable
    {
        #region Declaration(s)
        private Dictionary<string, DependencyProperty> DependencyProperties = new Dictionary<string, DependencyProperty>();
        #endregion

        #region Constructor(s)
        public Bindable()
        {
            CreateDependencyProperties();
        }
        #endregion

        #region Method(s)
        #region Public
        public void Set(object value, string propertyName)
        {
            this.SetValue(DependencyProperties[propertyName], value);
        }

        public int GetInt(string propertyName)
        {
            return (int)this.GetValue(DependencyProperties[propertyName]);
        }

        public string GetString(string propertyName)
        {
            return (string)this.GetValue(DependencyProperties[propertyName]);
        }

        public object GetObject(string propertyName)
        {
            return this.GetValue(DependencyProperties[propertyName]);
        }

        public object Get(string propertyName)
        {
            return this.GetValue(DependencyProperties[propertyName]);
        }

        public void NotifyPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler pceh = PropertyChanged;

            if (pceh != null)
            {
                pceh(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion


        #region Private
        private void CreateDependencyProperties()
        {
            Type type = this.GetType();
            PropertyInfo[] properties = type.GetProperties();
            Dictionary<string, DependencyProperty> tempDict = new Dictionary<string, DependencyProperty>();

            foreach (PropertyInfo pi in properties)
            {
                object[] attrib = pi.GetCustomAttributes(typeof(BindableAttribute), false);

                if (attrib.Length > 0)
                {
                    string propertyName = pi.Name;

                    if (!tempDict.ContainsKey(pi.Name))
                    {
                        tempDict.Add(pi.Name, null);

                        try
                        {
                            tempDict[pi.Name] = DependencyProperty.Register(pi.Name + "-xxx-" + Guid.NewGuid().ToString(), pi.PropertyType, pi.DeclaringType,
                            new PropertyMetadata(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
                            {
                                Bindable etvo = d as Bindable;
                                if (etvo != null)
                                {
                                    etvo.NotifyPropertyChanged(propertyName);
                                }
                            }));
                        }
                        catch { }
                        if (((BindableAttribute)attrib[0]).Initialize == true)
                        {
                            this.SetValue(tempDict[pi.Name], Activator.CreateInstance(pi.PropertyType));
                        }
                    }

                }
            }
            DependencyProperties = tempDict;
        }
        void ValidateProperty(string propertyName, object value)
        {
            var ctx = new ValidationContext(this, null, null);
            ctx.MemberName = propertyName;
            Validator.ValidateProperty(value, ctx);
            //Validator.ValidateObject(this, ctx);
        }
        #endregion
        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region IEnumerable Members

        public IEnumerator GetEnumerator()
        {
            return DependencyProperties.GetEnumerator();
        }

        #endregion
    }
}
